﻿using UnityEngine;
using System.Collections;
using System;

public class BrainCore : MonoBehaviour
{
	public static bool DISPLAY_NODE = false;
	public static float MIN_DELTA_TIME = 0.333f;
	public static float MAX_BUILD_COUNT = 5000000;
	static float MAX_NODE_DISTANCE=10;
	public static float VALUE_DEC_RATE = 0.5f;
	public static float THRESHOLD_INC_RATE = 0.0008f;
	public static float THRESHOLD_DEC_RATE = 0.75f;
	public static int MAX_UPDATE_BUILD_NUM = 40;
	public static int MAX_LINK_LIMIT = 3;

	public const sbyte ATTR_T = 0;// 土
	public const sbyte ATTR_J = 1;// 金
	public const sbyte ATTR_S = 2;// 水
	public const sbyte ATTR_M = 3;// 木
	public const sbyte ATTR_H = 4;// 火

	public static int count;
    private static float radus;

	Brainner bra;
	public sbyte attr;
    public float value;
	public float threshold;
	private sbyte stayCount;
	private sbyte lastStayCount;
	private MeshRenderer render;
	public bool thresholed;


    // Use this for initialization
    void Start()
    {
		bra = transform.parent.gameObject.GetComponent <Brainner>();
        radus = GetComponent<SphereCollider>().radius;
		render = GetComponent<MeshRenderer> ();
		//render.enabled = DISPLAY_NODE;
		lastStayCount = 0;
		stayCount = 0;
		value = 0;
		thresholed = false;
    }

//	void OnTriggerStay(Collider other)
//	{
//		if (other.gameObject.name.Equals ("Axon")) {
//			OnNodeTriggerStay (other.gameObject.transform.parent.gameObject.GetComponent<Collider>());
//		}
//	}

	public void OnNodeTriggerStay(BrainCore other)
	{
		if (other.gameObject == gameObject) {
			Debug.LogError ("self to self");
			return;
		}
		if (thresholed) {
			stayCount++;
			return;
		}
		if (other.transform.parent != transform.parent) {
			return;
		}
		BrainCore otherCore = other;

		float arate = 0;

		switch (attr) {
		case ATTR_H:
			if (ATTR_J == otherCore.attr)
				arate = -1f;
			if (ATTR_T == otherCore.attr)
				arate = 1f;
			break;
		case ATTR_T:
			if (ATTR_S == otherCore.attr)
				arate = -1f;
			if (ATTR_J == otherCore.attr)
				arate = 1f;
			break;
		case ATTR_J:
			if (ATTR_M == otherCore.attr)
				arate = -1f;
			if (ATTR_S == otherCore.attr)
				arate = 1f;
			break;
		case ATTR_S:
			if (ATTR_H == otherCore.attr)
				arate = -1f;
			if (ATTR_M == otherCore.attr)
				arate = 1f;
			break;
		case ATTR_M:
			if (ATTR_T == otherCore.attr)
				arate = -1f;
			if (ATTR_H == otherCore.attr)
				arate = 1f;
			break;
		}
		if (attr == otherCore.attr) {
			arate = 1f;
		}
		if (arate != 0) {
			stayCount++;
		}

		otherCore.addValue (arate);

		if (arate != 0 && value + threshold > 0 && stayCount <= MAX_LINK_LIMIT) {
			float distance = Vector3.Distance (transform.position, other.transform.position) - 1f;
			float tv = arate * (value + threshold);
//			if (float.IsNaN (tv)) {
//				Debug.LogError (" arate * (value + threshold) is NaN,  " + value + "," + threshold);
//			}
			float d = 3*radus;
			if (distance < 0) {
				distance = 0;
			}
			if (distance > d) {
				distance = d;
			}

			tv *= (d - distance) / d;
			otherCore.addValue (tv);

			tv = otherCore.value + otherCore.threshold;

			float rate = distance / d;
			float i = tv > 0 ? 0.01f : -0.0001f;
			other.transform.Translate ((transform.position - other.transform.position) * (i * rate));


		}
	}

	// Update is called once per frame
	void Update()
	{
		lastStayCount = stayCount;
		stayCount = 0;

		if (bra && bra.thresholds != 0) {
			threshold -= threshold*bra.thresholds;
		}

		if (!thresholed && value + threshold > 0) {
			thresholed = true;
			//render.material = Brainner.MaterialDef;
			if (DISPLAY_NODE)
				render.enabled = false;


			return;
		} else {
			
		}

		if (thresholed) {
			thresholed = false;
			threshold -= THRESHOLD_INC_RATE*(value+threshold);
			value = 0;

			if (DISPLAY_NODE)
				render.enabled = true;
		} else {
//			if (lastStayCount > MAX_LINK_LIMIT && gameObject.name.Equals ("Node(Clone)")) {
//				count--;
//				//Debug.Log ("Destroy "+other.gameObject.name+" "+other.transform.position);
//				Destroy (gameObject);
//				return;
//			}
		}

		if (threshold != 0) {
			threshold *= THRESHOLD_DEC_RATE;
		}

		if (value != 0) {
			value *= VALUE_DEC_RATE;
//			if (float.IsNaN(value)) {
//				Debug.LogError ("value *= VALUE_DEC_RATE,  value is NaN ");
//			}
		}

		if (Time.deltaTime < MIN_DELTA_TIME) {
			buildNode ();
		}

			


//		float distance = Vector3.Distance (transform.position, bra.transform.position) - 1f;
		// if(distance>MAX_NODE_DISTANCE)
		if (stayCount == 0 && value==0 && threshold ==0) {
			transform.Translate ((bra.transform.position-transform.position) * 0.0001f);
		}
	}

    public void addValue(float val)
	{
		if (float.IsInfinity(val) || thresholed) {
			return;
		}
		float before = value + threshold;

		value += val;

		if (float.IsInfinity (value)) {
			value = 0;
		}

//		if (float.IsNaN(value)) {
//			Debug.LogWarning ("value += val is NaN, val="+val);
//			value = 0;
//		}
//		float after = value + threshold;
//		if (before <= 0 && after > 0) {
//			//render.material = Brainner.MaterialLig;
//			render.enabled = DISPLAY_NODE;
//		} else if (val < 0) {
//			//render.material = Brainner.MaterialBlack;
//			if(DISPLAY_NODE)
//			render.enabled = false;
//		}
	}


	private sbyte buildCount;
	static float lastBuildTime;

    private void buildNode()
	{
		if (buildCount >= MAX_LINK_LIMIT || count >= MAX_BUILD_COUNT||Brainner.currFpsBuildCount>=MAX_UPDATE_BUILD_NUM) {
			return;
		}
		
		float rangeLen = 1f;
		float xr = UnityEngine.Random.Range (0, 100)>50 ?1:-1;
		float yr = UnityEngine.Random.Range (0, 100)>50 ?1:-1;
		float zr = UnityEngine.Random.Range (0, 100)>50 ?1:-1;
		Vector3 space = new Vector3 (UnityEngine.Random.Range (0, rangeLen)*xr+xr, UnityEngine.Random.Range (0, rangeLen)*yr+yr, UnityEngine.Random.Range (0, rangeLen)*zr+zr);
		GameObject node = (GameObject)Instantiate (bra.nodePre, transform.position + space, transform.rotation);
		BrainCore bcore = node.GetComponent<BrainCore> ();
		switch(attr){
		case ATTR_H:
			bcore.attr = UnityEngine.Random.Range(0,100)<50 ? ATTR_J : ATTR_T;
			break;
		case ATTR_T:
			bcore.attr = UnityEngine.Random.Range(0,100)<50 ? ATTR_S : ATTR_J;
			break;
		case ATTR_J:
			bcore.attr = UnityEngine.Random.Range(0,100)<50 ? ATTR_M : ATTR_S;
			break;
		case ATTR_S:
			bcore.attr = UnityEngine.Random.Range(0,100)<50 ? ATTR_H : ATTR_M;
			break;
		case ATTR_M:
			bcore.attr = UnityEngine.Random.Range(0,100)<50 ? ATTR_T : ATTR_H;
			break;
		}
		switch(bcore.attr){
		case ATTR_H:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (1f, 1f, 0, 0.3f);
			break;
		case ATTR_T:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (1f, 0.25f, 0, 0.3f);
			break;
		case ATTR_J:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0.8f, 0.8f, 0.8f, 0.3f);
			break;
		case ATTR_S:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0f, 0.75f, 1f, 0.3f);
			break;
		case ATTR_M:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0f, 0.5f, 0f, 0.3f);
			break;
		}
		node.transform.parent = transform.parent;
		bcore.GetComponent<MeshRenderer> ().enabled = DISPLAY_NODE;
		//node.GetComponent<MeshRenderer> ().enabled = false;
		Brainner.currFpsBuildCount++;
		buildCount++;
		count++;

	}


}